#pragma once 

#include<iostream>
#include<queue>
#include<mutex>
#include<pthread.h>
#include"lockGuard.hpp"

const int gDefaultGap = 5;

template<class T>
class BlockQueue
{
public:
//实现逻辑：锁和条件变量让构造和析构自行完成；设计生产者和消费者在共享区中的操作
    BlockQueue(int capacity = gDefaultGap):capacity_(capacity)
    {
        pthread_mutex_init(&mtx_,nullptr);
        pthread_cond_init(&Empty_,nullptr);
        pthread_cond_init(&Full_,nullptr);
    }

    //生产者
    void push(const T&in)
    {
        //1. 等待条件去访问临界资源
        //等待一定是在加锁和解锁中间进行；如果使用pthread_cond_wait（），需要注意第二个参数的使用
        lockGuard lockguard(&mtx_);//利用构造和析构，自动的加锁和解锁
        while(isQueueFull())//如果共享资源缓冲区的资源是满的则不生产
        {
            pthread_cond_wait(&Full_,&mtx_);
        }

        //2.访问临界资源
        bq_.push(in);
        pthread_cond_signal(&Empty_);//给消费者发送信号
    }

    void pop(T*out)
    {
        lockGuard lockguard(&mtx_);
        while(isQueueEmpty())
        {
            pthread_cond_wait(&Empty_,&mtx_);
        }
        //拿走队列中的首元素
        *out = bq_.front();
        bq_.pop();
        pthread_cond_signal(&Full_);
    }

    //析构
    ~BlockQueue()
    {
        pthread_mutex_destroy(&mtx_);
        pthread_cond_destroy(&Empty_);
        pthread_cond_destroy(&Full_);
    }

private:
    bool isQueueEmpty()
    {
        return bq_.size() ==0;
    }

    bool isQueueFull()
    {
        return bq_.size() ==capacity_;
    }

private:
    std::queue<T> bq_;//阻塞队列（临界资源）
    int capacity_;
    pthread_mutex_t mtx_;//互斥锁，保证队列的安全
    pthread_cond_t Empty_;//判空
    pthread_cond_t Full_;//判满
};